SWC编译器集成与Jest/Vitest测试配置
NestJS默认使用TypeScript编译器(TSC),速度较慢。SWC是一个用Rust编写的高速编译器,比TSC快约20倍。本节介绍如何在NestJS项目中集成SWC,以及Jest和Vitest测试框架的对比。
SWC简介
SWC(Speedy Web Compiler)是一个基于Rust的JavaScript/TypeScript编译器,核心优势:
- 比TSC快约20倍
- 支持TypeScript语法转译
- 支持JSX转换
- 可作为Webpack/Vite插件使用
重要说明:SWC默认跳过类型检查以获得极致速度,但可以在构建时单独开启。
安装SWC
pnpm install --save-dev @swc/cli @swc/core
bash
方式一:命令行指定SWC
在package.json的脚本中加上-b swc参数:
{
"scripts": {
"start:dev": "nest start -b swc",
"build": "nest build -b swc"
}
}
json
方式二:全局配置(推荐)
在nest-cli.json中配置,避免每个脚本都加参数:
{
"compilerOptions": {
"builder": "swc"
}
}
json
配置后,所有nest命令自动使用SWC编译器,无需修改package.json。
也可以通过对象形式自定义构建器行为:
{
"compilerOptions": {
"builder": {
"type": "swc",
"options": {
"swcrcPath": "infrastructure/.swcrc"
}
}
}
}
json
编译速度对比
| 编译器 | 开发启动 | 构建 |
|---|---|---|
| TSC(默认) | 较慢(~500ms+) | 慢(~1s+) |
| SWC | 极快(~53ms) | 极快(~62ms) |
| SWC + type-check | 快(~171ms) | 快 |
SWC配置文件
在项目根目录创建.swcrc文件:
{
"jsc": {
"parser": {
"syntax": "typescript",
"decorators": true
},
"transform": {
"legacyDecorator": true,
"decoratorMetadata": true
},
"target": "es2021",
"keepClassNames": true,
"minify": {
"mangle": false,
"compress": false
}
},
"module": {
"type": "commonjs"
}
}
json
类型检查配置
SWC默认不做类型检查。推荐方案:
- 开发时:依靠IDE(VS Code/WebStorm)的内置TypeScript检查
- 构建时:开启SWC的类型检查
nest start -b swc --type-check
bash
或在nest-cli.json中配置:
{
"compilerOptions": {
"builder": "swc",
"typeCheck": true
}
}
json
--type-check 标志会自动执行 NestJS CLI 插件并生成序列化的元数据文件,供运行时加载使用。
建议:不在全局开启type-check,只在CI/CD构建脚本中使用,避免拖慢开发体验。
路径别名配置
在tsconfig.json中配置路径别名:
{
"compilerOptions": {
"paths": {
"@/*": ["src/*"],
"@swc/*": ["src/*"]
}
}
}
json
这样就可以在代码中使用@/代替相对路径:
import { UserService } from '@/modules/user/user.service';
typescript
Jest集成SWC
pnpm install --save-dev @swc/jest
bash
修改package.json中的Jest配置:
{
"jest": {
"transform": {
"^.+\\.(t|j)s$": "@swc/jest"
}
}
}
json
.swcrc 中需要额外配置 legacyDecorator 和 decoratorMetadata:
{
"jsc": {
"transform": {
"legacyDecorator": true,
"decoratorMetadata": true
}
}
}
json
Vitest集成SWC
pnpm install --save-dev vitest unplugin-swc @swc/core
bash
创建vitest.config.ts:
import swc from 'unplugin-swc';
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
globals: true,
root: './',
},
plugins: [
swc.vite({
module: { type: 'es6' },
}),
],
});
typescript
E2E 测试需要单独的配置文件,增加 include 字段:
import swc from 'unplugin-swc';
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
include: ['**/*.e2e-spec.ts'],
globals: true,
root: './',
},
plugins: [swc.vite()],
});
typescript
注意事项:
- 需要将端到端测试中的
import * as request from 'supertest'改为import request from 'supertest' - 需要设置
NODE_ENV=test
Jest vs Vitest性能对比
在相同项目中的实测数据:
| 框架 | 配合SWC | 测试耗时 | 兼容性 |
|---|---|---|---|
| Jest + SWC | 是 | ~800ms-1.1s | 原生支持NestJS |
| Vitest + SWC | 是 | ~900ms-1.2s | 需额外配置 |
结论:在NestJS项目中,Jest + SWC的组合比Vitest + SWC稍快,且配置更简单。Vitest的优势在于Vite生态和HMR支持,更适合前端项目。
Monorepo 场景
如果项目是 monorepo 结构,必须配置 webpack 使用 swc-loader:
pnpm install --save-dev swc-loader
bash
创建 webpack.config.js:
const swcDefaultConfig = require('@nestjs/cli/lib/compiler/defaults/swc-defaults').swcDefaultsFactory().swcOptions;
module.exports = {
module: {
rules: [
{
test: /\.ts$/,
exclude: /node_modules/,
use: {
loader: 'swc-loader',
options: swcDefaultConfig,
},
},
],
},
};
javascript
常见陷阱:循环依赖
如果使用 TypeORM/MikroORM,可能遇到 SWC 的循环导入问题。解决方案是使用 Relation<> 包装类型:
import { Relation } from 'typeorm';
@Entity()
export class User {
@OneToOne(() => Profile, (profile) => profile.user)
profile: Relation<Profile>; // 使用 Relation<> 而非直接写 Profile
}
typescript
对于依赖注入中的循环依赖,也需要类似处理:
export type WrapperType<T> = T;
@Injectable()
export class UserService {
constructor(
@Inject(forwardRef(() => ProfileService))
private readonly profileService: WrapperType<ProfileService>,
) {}
}
typescript
最终推荐配置
本项目选择 Jest + SWC 方案:
# 安装依赖
pnpm install --save-dev @swc/cli @swc/core @swc/jest
bash
// nest-cli.json
{
"compilerOptions": {
"builder": "swc"
}
}
json
// package.json 关键脚本
{
"scripts": {
"start:dev": "nest start --watch",
"build": "nest build",
"build:check": "nest build --type-check",
"test": "jest",
"test:watch": "jest --watch",
"test:e2e": "jest --config ./test/jest-e2e.json"
}
}
json
↑